package com.xzzz.common.wechat.manager;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.util.StringUtils;
import com.xzzz.common.base.exception.XzException500;
import com.xzzz.common.base.util.json.JsonUtil;
import com.xzzz.common.base.util.okhttp.HttpUtil;
import com.xzzz.common.wechat.enums.WxErrorCode;
import com.xzzz.common.wechat.pojo.WxBaseDTO;
import lombok.extern.slf4j.Slf4j;

import java.util.MissingFormatArgumentException;

/**
 * @author xzzz
 *
 */
@Slf4j
public abstract class AbstractWxManager {

    /**
     * GET请求获取响应体字符串
     *
     * @param url   请求链接,通过 {@link String#format} 格式化
     * @param value 参数集合
     * @return 响应体
     */
    protected String getBody(String url, Object... value) {
        try {
            String requestUrl = String.format(url, value);
            log.debug("[微信功能] GET请求链接: {}", requestUrl);

            String body = HttpUtil.get(requestUrl);
            if (StrUtil.isBlank(body)) {
                log.error("[微信功能] 未收到微信接口响应: {}", url);
                throw new XzException500("未收到微信接口响应");
            }
            return body;
        } catch (MissingFormatArgumentException e) {
            e.printStackTrace();
            log.error("[微信功能] 微信请求的URL参数个数错误: 请求链接: {}, 错误信息: {}", url, e.getMessage());
            throw new XzException500("微信请求的URL参数个数错误");
        }
    }


    /**
     * 发送Post请求
     *
     * @param wxBaseDTO 微信基础对象
     * @return 返回值
     */
    protected String postBody(String url, WxBaseDTO wxBaseDTO, String appId) {
        log.debug("[微信功能] POST请求对象: {}", wxBaseDTO);
        try {
            String body = HttpUtil.post(fillToken(url, appId), JsonUtil.toJson(wxBaseDTO));
            if (StringUtils.isBlank(body)) {
                log.error("[微信功能] 未收到微信接口响应: {}", url);
                throw new XzException500("未收到微信接口响应");
            }
            return body;
        } catch (MissingFormatArgumentException e) {
            e.printStackTrace();
            log.error("[微信功能] 微信请求的URL参数个数错误: 请求链接: {}, 错误信息: {}", url, e.getMessage());
            throw new XzException500("微信请求的URL参数个数错误");
        }
    }


    /**
     * post请求返回流
     *
     * @param url       url
     * @param wxBaseDTO wxBaseDTO
     * @param appId     微信 appId
     * @return 返回对象
     */
    protected byte[] postBodyGetBytes(String url, WxBaseDTO wxBaseDTO, String appId) {
        url = fillToken(url, appId);
        log.debug("[微信功能] POST请求地址: {}", url);
        log.debug("[微信功能] POST请求对象: {}", JsonUtil.toJson(wxBaseDTO));
        try {
            byte[] bytes = HttpUtil.postResponseBytes(fillToken(url, appId), JsonUtil.toJson(wxBaseDTO));
            if (bytes.length == 0) {
                log.error("[微信功能] 获取微信响应流长度为0: 请求链接: {}", url);
                throw new XzException500("获取微信响应流失败");
            }
            return bytes;
        } catch (MissingFormatArgumentException e) {
            e.printStackTrace();
            log.error("[微信功能] 微信请求的URL参数个数错误: 请求链接: {}, 错误信息: {}", url, e.getMessage());
            throw new XzException500("微信请求的URL参数个数错误");
        }
    }

    /**
     * 检查接口响应,不重试
     *
     * @param wxBaseDTO 微信基础dto
     */
    protected void checkResult(WxBaseDTO wxBaseDTO) {
        checkResult(wxBaseDTO, false);
    }

    /**
     * 检查接口响应
     * 如果微信token无效不会抛出异常,而是返回true,调用方可以凭借此来判断是否需要重试
     *
     * @param wxBaseDTO 微信基础dto
     * @param retry     是否继续重试
     * @return retry 是否需要重试
     */
    protected boolean checkResult(WxBaseDTO wxBaseDTO, boolean retry) {
        if (null == wxBaseDTO) {
            throw new XzException500("[微信功能] 请求微信时响应无法转换实体");
        }

        // 正确的请求
        if (null == wxBaseDTO.getErrcode() || WxErrorCode.isSucc(wxBaseDTO.getErrcode())) {
            return false;
        }

        // token失效,返回重试
        if (wxBaseDTO.getErrcode().equals(WxErrorCode.SECRET_ERROR.getCode()) && retry) {
            return true;
        }

        // token失效,返回重试
        if (wxBaseDTO.getErrcode().equals(WxErrorCode.TOKEN_EXPIRE.getCode()) && retry) {
            return true;
        }

        String errorMsg = WxErrorCode.getMsg(wxBaseDTO.getErrcode());
        if (StringUtils.isBlank(errorMsg)) {
            errorMsg = StringUtils.isNotBlank(wxBaseDTO.getErrmsg()) ? wxBaseDTO.getErrmsg() : "请求微信发生未知异常";
        }

        log.error("[微信功能] 请求微信异常: 错误码: {}, 错误信息: {}", wxBaseDTO.getErrcode(), errorMsg);
        throw new XzException500(errorMsg);
    }


    /**
     * 适用于POST请求链接中添加调用凭证
     *
     * @param url 请求链接
     * @return 添加调用凭证后的URL
     */
    private String fillToken(String url, String appId) {
        return String.format(url, getAuthAccessToken(appId));
    }


    /**
     * 获取调用凭证
     *
     * @param appId appId
     * @return 调用凭证
     */
    protected abstract String getAuthAccessToken(String appId);
}
